﻿#include "diskthread.h"
#include <QDebug>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <linux/types.h>
#include <linux/netlink.h>

#define UEVENT_BUFFER_SIZE          (2048)
#define UDISK_PATH                  ("/udisk")

DiskThread::DiskThread(QObject *parent) : QThread(parent)
{
    struct sockaddr_nl snl;
    const int buffersize = 16 * 1024 * 1024;
    int retval;

    qRegisterMetaType<DiskStatus>("DiskStatus");

    memset(&snl, 0x00, sizeof(struct sockaddr_nl));
    snl.nl_family = AF_NETLINK;
    snl.nl_pid = getpid();
    snl.nl_groups = 1;
    int hotplug = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (hotplug == -1) {
        qDebug()<<"error getting socket:"<<strerror(errno);
        hotplug_sock = -1;

        return ;
    }
    /* set receive buffersize */
    setsockopt(hotplug, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
    retval = bind(hotplug, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
    if (retval < 0) {
        qDebug()<<"bind failed:"<<strerror(errno);
        close(hotplug);
        hotplug = -1;
        hotplug_sock = -1;

        return ;
    }
    hotplug_sock = hotplug;
}

DiskThread::~DiskThread()
{
    hotplug_sock = -1;
}

bool DiskThread::updataUsb()
{
    QString output;
    MCommon::ShellProcess("df", QStringList()<<"-h", output);

    QStringList itemList;
    getRegExp("/dev/sd[a-z].*/media/usb.*\\n", output, itemList);
    if (itemList.length() == 0)
        return false;

    //for (int i=0; i<itemList.length(); i++) {
    //    qDebug()<<itemList.at(i);
    //}
    emit diskStatusSignal(UDISK_ADD, UDISK_PATH);

    return true;
}

int DiskThread::getRegExp(const QString pattern, const QString &text, QStringList &list)
{
    QRegExp regExp;
    int capCount = 0;
    int pos = 0;

    if (pattern.isEmpty() || text.isEmpty())
        return -1;

    regExp.setMinimal(true);
    regExp.setPattern(pattern);
    regExp.indexIn(text);

    list.clear();
    while ((pos = regExp.indexIn(text, pos)) != -1)
    {
        list.push_back(regExp.cap(0));
        pos += regExp.matchedLength();
        capCount++;
    }

    return capCount;
}

void DiskThread::run()
{
    char buf[UEVENT_BUFFER_SIZE*2] = {0};
    QString msg;

    msleep(1000);

    if (updataUsb()) {
        diskStatus = true;
    }
    fcntl(hotplug_sock, F_SETFL, fcntl(hotplug_sock, F_GETFL, 0));

    for ( ; 1 ; )
    {
        if (hotplug_sock < 0)
            break;
        int len = read(hotplug_sock, buf, UEVENT_BUFFER_SIZE*2);
        if(len < 0)
            continue;

        msg = QString::fromLocal8Bit(buf, len);
        if(msg.startsWith("add") && diskStatus != true)
        {
            diskStatus = true;
            for (int i=0; i<300; i++)
            {//3s检测时间
                if (updataUsb())
                    break;
                msleep(10);
            }
        }
        else if(msg.startsWith("remove") && diskStatus != false)
        {
            diskStatus = false;
            emit diskStatusSignal(UDISK_REMOVE, "");
        }
    }
}
